﻿using System.Dynamic;
using System.Linq.Expressions;

namespace DLR05
{
    /// <summary>
    /// A dynamic expression must have a DynamicMetaObjectBinder class to act on.
    /// This class ensures that two dynamic values can be added together, and
    /// creates the result.
    /// </summary>
    public class SimpleBinaryOperationBinder : BinaryOperationBinder
    {
        public SimpleBinaryOperationBinder(ExpressionType expressionType)
            : base(expressionType)
        {
        }

        /// <summary>
        /// This is called to make sure the two dynamic values are added together somehow.
        /// </summary>
        public override DynamicMetaObject FallbackBinaryOperation(DynamicMetaObject target, DynamicMetaObject arg, DynamicMetaObject errorSuggestion)
        {
            if (!target.HasValue || !arg.HasValue)
            {
                return Defer(target, arg);
            }

            var restrictions = target.Restrictions
                .Merge(arg.Restrictions)
                .Merge(BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType))
                .Merge(BindingRestrictions.GetTypeRestriction(arg.Expression, arg.LimitType));

            return new DynamicMetaObject(
                ExpressionEx.EnsureObjectResult(Expression.MakeBinary(
                    Operation,
                    Expression.Convert(target.Expression, target.LimitType),
                    Expression.Convert(arg.Expression, arg.LimitType)
                )),
                restrictions
            );
        }
    }
}